function DownloadManager()  { // handles file download queue

  /*
    Due to the asynchronous nature of the jQuery .ajax() function, this
    section includes many variables that are set for each download activity
    then erased at the end
  */

  // passing variables between functions in this class
  this.currentTargetFolder = "";
  this.passedId = "";
  this.downloadQueue = [];
  this.currentFileId = "";
  this.downloadData = "";
  this.downloadFolder = "";
  this.downloadName = "";
  this.downloadComplete = 1;

  // function to take various formats of download id (folder, file(s) etc) and get target folder
  this.startDownload = function(id) {

    if ((download.passedId == "") && (uploader.uploading == "0")) {

      this.passedId = id;

      targetFolder = new air.File();
      
      if (isArray(id)) { // if id is from selector class so contains more than one file for download
      
        targetFolder.addEventListener(air.Event.SELECT, download.queueDownloadFiles);
        targetFolder.addEventListener(air.Event.CANCEL, download.abort);
        targetFolder.browseForDirectory("Where would you like to put these files?");
        
      } else {
      
        tempId = sortTypeId("unknown", id);
        type = tempId[0];

        if (type == "folder") { // if a folder id has been passed so we want the folder contents
        
          this.passedId = tempId[1];
        
          targetFolder.addEventListener(air.Event.SELECT, download.queueDownloadFolder);
          targetFolder.addEventListener(air.Event.CANCEL, download.abort);
          targetFolder.browseForDirectory("Where would you like to put the contents of this folder?");

        } else { // if its just a single file
        
          targetFolder.addEventListener(air.Event.SELECT, download.queueDownloadFile);
          targetFolder.addEventListener(air.Event.CANCEL, download.abort);
          targetFolder.browseForDirectory("Where would you like to put this file?");

        }
      
      }
      
      // sets the current folder
      this.currentTargetFolder = targetFolder;
      
    }

  }
  
  // function to reset all the variables if the cancel button is pressed on the choose folder dialog
  this.abort = function() {
  
    // reset all the variables
    download.currentTargetFolder = "";
    download.passedId = "";
    download.downloadQueue = [];
    download.currentFileId = "";
    download.downloadData = "";
    download.downloadFolder = "";
    download.downloadName = "";
    download.downloadComplete = 1;

    msgs.unlock();

  }

  // handler for the array of files
  this.queueDownloadFiles = function() {
    
    ids = download.passedId;
    
    for (x in ids) {
    
      download.downloadQueue.push(ids[x]);
    
    }
    
    msgs.display("Downloading", -1);
    download.doNextDownload(); // start the download loop

  }

  // handler for downloading a folder's contents
  this.queueDownloadFolder = function() {
    
    // gets the contents of the folder
    json.getData("folder", download.processFolderData, download.passedId);

  }

  // takes the list of files from the queueDownloadFolder function and queues
  this.processFolderData = function(data) {

    items = data.Data;
    
    localArray = [];
    
    for (x in items) {

      if (items[x].Type == "File") {

        localArray.push(items[x].Id);
        
      }
    
    }
    
    download.passedId = localArray;

    download.queueDownloadFiles(); // takes the array and puts though multiple file function to put into queue

  }
  
  // handler for single file download
  this.queueDownloadFile = function() {

    temp = sortTypeId("unknown", download.passedId);
    
    download.downloadQueue.push(temp[1]); // adds it to queue (for consistency)
    
    msgs.display("Downloading", -1);
    download.doNextDownload(); // starts download loop

  }
  
  // download loop - continually calls until no files left in queue
  this.doNextDownload = function() {

    if (download.downloadQueue.length > 0) { // if files exist in queue

      currentFile = download.downloadQueue.pop();
      
      this.currentFileId = currentFile;
      this.downloadFile(); // download the current file
      
    } else { // if no files left

      // reset all the variables
      this.currentTargetFolder = "";
      this.passedId = "";
      this.downloadQueue = [];
      this.currentFileId = "";
      this.downloadData = "";
      this.downloadFolder = "";
      this.downloadName = "";
      this.downloadComplete = 1;

      msgs.unlock();
    
    }

  }

  // takes file ID and begins download for it
  this.downloadFile = function() {

    this.downloadComplete = 0;

    id = this.currentFileId;

    this.downloadTheData(id); // downloads the file data itself
    json.getData("file", download.handleFileData, id); // asynchronously gets file details using separate API call

  }

  // sets the file name from asynchronous request (while download is actually happening)
  this.handleFileData = function(data) {

    download.downloadName = data.Data.FileName;

  }

  // handle the data that's been downloaded
  this.handleDownloadData = function(data) {

    this.downloadData = data;
    
  }
  
  // rounds off the file download once all the data has been collected
  this.completeFileDownload = function() {

    if ((this.downloadData != "") && (this.downloadName != "")) { // required values have been set

      targetFolder = download.currentTargetFolder;
      
      name = download.downloadName;

      theFile = targetFolder.resolvePath(name);

      // writes the file downloaded to the hard drive
      var fileStream = new air.FileStream();
      fileStream.open(theFile, air.FileMode.WRITE);
      fileStream.writeBytes(this.downloadData);
      fileStream.close();  
      
      // resets some variables for next download
      download.downloadData = "";
      download.downloadFolder = "";
      download.downloadName = "";
      
      // does next download in queue
      download.doNextDownload();
      
    } else {

      // if the two values aren't set, it waits until it is
      setTimeout(download.completeFileDownload, 100);
      
    }

  }

  // downloads the data
  this.downloadTheData = function(id) {

    // sets login credentials (this can only be done once per app session, additional calls won't change the details)
    air.URLRequestDefaults.setLoginCredentialsForHost("api.huddle.net", huddle.getUsername(), huddle.getPassword());

    // request forming
    var airRequest = new air.URLRequest("https://api.huddle.net/v1/json/files/" + id + "/download");

    airRequest.method = air.URLRequestMethod.GET;
    
    loader = new air.URLLoader();
    
    loader.dataFormat = air.URLLoaderDataFormat.BINARY;

    // event listener waiting for file to be downloaded
    loader.addEventListener(air.Event.COMPLETE, function(event) {
      theResponse = event.target;
      someData = theResponse.data;
      this.downloadData = someData;
      this.downloadComplete = 1;
      download.completeFileDownload(); // calls complete function when done
    });
    
    // on error, reset
    loader.addEventListener(air.IOErrorEvent.IO_ERROR, function(event) {
      // reset all the variables
      this.currentTargetFolder = "";
      this.passedId = "";
      this.downloadQueue = [];
      this.currentFileId = "";
      this.downloadData = "";
      this.downloadFolder = "";
      this.downloadName = "";
      this.downloadComplete = 1;

      msgs.unlock();
    });

    loader.load(airRequest); // does request

  }
  
  /*
    this method exists due to a problem that exists only in few conditions - 
    without it, if you try to upload a file without downloading one first
    the Air application fails to sent the authenciation details properly
    and fails the upload without retrying. This method does a dummy download when
    login is initialised so that when it tries an upload it sends authorisation.
  */
  this.authenticates = function() {
  
    // sets login credentials (this can only be done once per app session, additional calls won't change the details)
    air.URLRequestDefaults.setLoginCredentialsForHost("api.huddle.net", huddle.getUsername(), huddle.getPassword());

    // request forming
    var airRequest = new air.URLRequest("https://api.huddle.net/v1/json/workspaces");

    airRequest.method = air.URLRequestMethod.GET;
    
    loader = new air.URLLoader();
    
    loader.dataFormat = air.URLLoaderDataFormat.BINARY;

    loader.load(airRequest); // does request
  
  }
  
}